use crate::options::{Opt, OPTS};
use pnet;
use std::io::Result as IOResult;
use std::process::{Command, ExitStatus, ExitCode};

pub fn build_iptables_clear_nat() -> String {
    format!("sudo iptables -t nat -F")
}

pub fn build_iptables_add_root_dnat(root_net_ip: &str) -> String {
    // Lookup interface by ip
    let mut root_net_iface = String::new();
    for iface in pnet::datalink::interfaces() {
        for ip in iface.ips {
            if ip.is_ipv4() && ip.ip().to_string() == root_net_ip {
                root_net_iface = iface.name.clone();
            }
        }
    }
    if root_net_iface.is_empty() {
        return format!("echo -n");
    }
    println!("root net interface [{}]", root_net_iface);

    let mut cmds: Vec<String> = Vec::new();
    for tcp_port in OPTS.server_tcp_port.iter() {
        let tcp_cmd = format!(
            "sudo iptables -A PREROUTING -i {} -t nat -p tcp -d {} --dport {} -j DNAT --to-destination 100.64.0.2",
            root_net_iface, root_net_ip, tcp_port);
        cmds.push(tcp_cmd);

        if root_net_iface != "lo" {
            let tcp_cmd = format!(
                "sudo iptables -A OUTPUT -t nat -p tcp --dport {} -j DNAT --to-destination 100.64.0.2",
                 tcp_port);
            cmds.push(tcp_cmd);
        }
    }
    for udp_port in OPTS.server_udp_port.iter() {
        let udp_cmd = format!(
            "sudo iptables -A PREROUTING -i {} -t nat -p udp -d {} --dport {} -j DNAT --to-destination 100.64.0.2",
            root_net_iface, root_net_ip, udp_port);
        cmds.push(udp_cmd);

        if root_net_iface != "lo" {
            let udp_cmd = format!(
                "sudo iptables -A OUTPUT -t nat -p udp --dport {} -j DNAT --to-destination 100.64.0.2",
                udp_port);
            cmds.push(udp_cmd);
        }
    }
    cmds.join(" && ")

    // let tcp_cmd = format!("sudo iptables -A PREROUTING -i {} -t nat -p tcp -d {} --dport 5080 -j DNAT --to-destination 100.64.0.2", root_net_iface, root_net_ip);
    // let udp_cmd = format!("sudo iptables -A PREROUTING -i {} -t nat -p udp -d {} --dport 9360 -j DNAT --to-destination 100.64.0.2", root_net_iface, root_net_ip);
    // format!("{} && {}", tcp_cmd, udp_cmd)
}

pub fn iptables_clear_nat() -> IOResult<ExitCode> {
    // iptables -t nat -F
    Command::new("sudo")
        .arg("iptables")
        .args(["-t", "nat", "-F"])
        .status()?;
    Ok(ExitCode::SUCCESS)
}

pub fn iptables_add_root_dnat(root_net_ip: &str) -> IOResult<ExitCode> {
    // Lookup interface by ip
    let mut root_net_iface = String::new();
    for iface in pnet::datalink::interfaces() {
        for ip in iface.ips {
            if ip.is_ipv4() && ip.ip().to_string() == root_net_ip {
                root_net_iface = iface.name.clone();
            }
        }
    }
    if root_net_iface.is_empty() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::AddrNotAvailable,
            format!("interface with ip {} not found", root_net_ip),
        ));
    }
    println!("root net interface [{}]", root_net_iface);

    for tcp_port in OPTS.server_tcp_port.iter() {
        // iptables -A PREROUTING -i ens192 -t nat -p tcp -d 192.168.6.53 --dport 5080 -j DNAT --to-destination 100.64.0.2
        Command::new("sudo")
            .arg("iptables")
            .args(["-A", "PREROUTING", "-i", &root_net_iface, "-t", "nat"])
            .args([
                "-p",
                "tcp",
                "-d",
                root_net_ip,
                "--dport",
                tcp_port.to_string().as_str(),
                "-j",
                "DNAT",
            ])
            .args(["--to-destination", "100.64.0.2"])
            .status()?;
    }

    for udp_port in OPTS.server_udp_port.iter() {
        // iptables -A PREROUTING -i ens192 -t nat -p udp -d 192.168.6.53 --dport 9360 -j DNAT --to-destination 100.64.0.2
        Command::new("sudo")
            .arg("iptables")
            .args(["-A", "PREROUTING", "-i", &root_net_iface, "-t", "nat"])
            .args([
                "-p",
                "udp",
                "-d",
                root_net_ip,
                "--dport",
                udp_port.to_string().as_str(),
                "-j",
                "DNAT",
            ])
            .args(["--to-destination", "100.64.0.2"])
            .status()?;
    }
    Ok(ExitCode::SUCCESS)
}
